#include "DecoRigidBody.h"
#include "GridField.h"
#include "FluidSparseVector.h"
#include "DecoLogger.h"

DecoRigidObject::DecoRigidObject()
:	m_segments(0),
	m_oneLoopTime(0),
	m_phaseAcc(NULL),
	m_phaseVel(NULL),
	m_phaseOmg(NULL),
	m_phaseDuration(NULL)
{
	objType = SolidT;
	m_vel = vector3(0, -1, 0);
	//m_omg = vector3(0, 0, 0.5);
}

DecoRigidObject::~DecoRigidObject(void)
{
	destroyAllArrays();
}

vector3 DecoRigidObject::SampleVelocity(const vector3& pos)
{
	matrix44 localToWorld = coords.GetMatrix();

	vector3 vel(m_vel);
	vector3 rotateAxis = m_omg;
	rotateAxis.normalize();
	vector4 homoOrigin = vector4(0, 0, 0, 1);
	vector4 homoRotateOrigin = localToWorld * homoOrigin;
	vector3 rotateOrigin(homoRotateOrigin.x, homoRotateOrigin.y, homoRotateOrigin.z);

	vector3 posLocal = pos - rotateOrigin;
	vector3 proj = DotProduct(posLocal, rotateAxis) * rotateAxis;
	vector3 r = posLocal - proj;
	vel += CrossProduct(m_omg, r);
	return vel;
}

void DecoRigidObject::PrepareImplicitTwowayCouplingMatrix(int dim)
{
	prepareCouplingMatrixForRigidBody(dim);
	//if (m_bTwowayCouple)
	//{
	//	m_ForceX.SetDimension(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//	m_ForceY.SetDimension(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//	m_ForceZ.SetDimension(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//	m_TorqueX.SetDimension(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//	m_TorqueY.SetDimension(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//	m_TorqueZ.SetDimension(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//	m_ForceX.SetZero();
	//	m_ForceY.SetZero();
	//	m_ForceZ.SetZero();
	//	m_TorqueX.SetZero();
	//	m_TorqueY.SetZero();
	//	m_TorqueZ.SetZero();


	//	int numAssociatedCells = static_cast<int>(m_associateGridIndex.size());
	//	double area = m_grid->stepSize * m_grid->stepSize;
	//	vector3 force, dirFromOrigin, torque;
	//	for (int it = 0; it < numAssociatedCells; ++it)
	//	{
	//		int i = m_associateGridIndex[it].m_i;
	//		int j = m_associateGridIndex[it].m_j;
	//		int k = m_associateGridIndex[it].m_k;
	//		if (m_grid->isFluidCell(i + 1, j, k))
	//		{
	//			vector3 normal = vector3(-1, 0, 0);
	//			vector3 posGlobal = m_grid->GetGridCenter(i + 1, j, k) + vector3(-m_grid->stepSize / 2, 0, 0);
	//			dirFromOrigin = posGlobal - m_COM;
	//			dirFromOrigin.normalize();
	//			torque = CrossProduct(dirFromOrigin, normal) * area;

	//			m_ForceX.SetValue(i + 1, j, k, m_ForceX.GetValue(i + 1, j, k) - area);

	//			m_TorqueX.SetValue(i + 1, j, k, m_TorqueX.GetValue(i + 1, j, k) + torque.x);
	//			m_TorqueY.SetValue(i + 1, j, k, m_TorqueY.GetValue(i + 1, j, k) + torque.y);
	//			m_TorqueZ.SetValue(i + 1, j, k, m_TorqueZ.GetValue(i + 1, j, k) + torque.z);
	//		}
	//		if (m_grid->isFluidCell(i - 1, j, k))
	//		{
	//			vector3 normal = vector3(1, 0, 0);
	//			vector3 posGlobal = m_grid->GetGridCenter(i - 1, j, k) + vector3(m_grid->stepSize / 2, 0, 0);
	//			dirFromOrigin = posGlobal - m_COM;
	//			dirFromOrigin.normalize();
	//			torque = CrossProduct(dirFromOrigin, normal) * area;

	//			m_ForceX.SetValue(i - 1, j, k, m_ForceX.GetValue(i - 1, j, k) + area);

	//			m_TorqueX.SetValue(i - 1, j, k, m_TorqueX.GetValue(i - 1, j, k) + torque.x);
	//			m_TorqueY.SetValue(i - 1, j, k, m_TorqueY.GetValue(i - 1, j, k) + torque.y);
	//			m_TorqueZ.SetValue(i - 1, j, k, m_TorqueZ.GetValue(i - 1, j, k) + torque.z);

	//		}
	//		if (m_grid->isFluidCell(i, j + 1, k))
	//		{
	//			vector3 normal = vector3(0, -1, 0);
	//			vector3 posGlobal = m_grid->GetGridCenter(i, j + 1, k) + vector3(0, -m_grid->stepSize / 2, 0);
	//			dirFromOrigin = posGlobal - m_COM;
	//			dirFromOrigin.normalize();
	//			torque = CrossProduct(dirFromOrigin, normal) * area;

	//			m_ForceY.SetValue(i, j + 1, k, m_ForceY.GetValue(i, j + 1, k) - area);

	//			m_TorqueX.SetValue(i, j + 1, k, m_TorqueX.GetValue(i, j + 1, k) + torque.x);
	//			m_TorqueY.SetValue(i, j + 1, k, m_TorqueY.GetValue(i, j + 1, k) + torque.y);
	//			m_TorqueZ.SetValue(i, j + 1, k, m_TorqueZ.GetValue(i, j + 1, k) + torque.z);

	//		}
	//		if (m_grid->isFluidCell(i, j - 1, k))
	//		{
	//			vector3 normal = vector3(0, 1, 0);

	//			vector3 posGlobal = m_grid->GetGridCenter(i, j - 1, k) + vector3(0, m_grid->stepSize / 2, 0);
	//			dirFromOrigin = posGlobal - m_COM;
	//			dirFromOrigin.normalize();
	//			torque = CrossProduct(dirFromOrigin, normal) * area;

	//			m_ForceY.SetValue(i, j - 1, k, m_ForceY.GetValue(i, j - 1, k) + area);

	//			m_TorqueX.SetValue(i, j - 1, k, m_TorqueX.GetValue(i, j - 1, k) + torque.x);
	//			m_TorqueY.SetValue(i, j - 1, k, m_TorqueY.GetValue(i, j - 1, k) + torque.y);
	//			m_TorqueZ.SetValue(i, j - 1, k, m_TorqueZ.GetValue(i, j - 1, k) + torque.z);

	//		}
	//		if (m_grid->isFluidCell(i, j, k + 1))
	//		{
	//			vector3 normal = vector3(0, 0, -1);

	//			vector3 posGlobal = m_grid->GetGridCenter(i, j, k + 1) + vector3(0, 0, -m_grid->stepSize / 2);
	//			dirFromOrigin = posGlobal - m_COM;
	//			dirFromOrigin.normalize();
	//			torque = CrossProduct(dirFromOrigin, normal) * area;

	//			m_ForceZ.SetValue(i, j, k + 1, m_ForceZ.GetValue(i, j, k + 1) - area);

	//			m_TorqueX.SetValue(i, j, k + 1, m_TorqueX.GetValue(i, j, k + 1) + torque.x);
	//			m_TorqueY.SetValue(i, j, k + 1, m_TorqueY.GetValue(i, j, k + 1) + torque.y);
	//			m_TorqueZ.SetValue(i, j, k + 1, m_TorqueZ.GetValue(i, j, k + 1) + torque.z);

	//		}
	//		if (m_grid->isFluidCell(i, j, k - 1))
	//		{
	//			vector3 normal = vector3(0, 0, 1);

	//			vector3 posGlobal = m_grid->GetGridCenter(i, j, k - 1) + vector3(0, 0, m_grid->stepSize / 2);
	//			dirFromOrigin = posGlobal - m_COM;
	//			dirFromOrigin.normalize();
	//			torque = CrossProduct(dirFromOrigin, normal) * area;

	//			m_ForceZ.SetValue(i, j, k - 1, m_ForceZ.GetValue(i, j, k - 1) + area);

	//			m_TorqueX.SetValue(i, j, k - 1, m_TorqueX.GetValue(i, j, k - 1) + torque.x);
	//			m_TorqueY.SetValue(i, j, k - 1, m_TorqueY.GetValue(i, j, k - 1) + torque.y);
	//			m_TorqueZ.SetValue(i, j, k - 1, m_TorqueZ.GetValue(i, j, k - 1) + torque.z);

	//		}
	//	}
	//	m_ForceX /= m_mass;
	//	m_ForceY /= m_mass;
	//	m_ForceZ /= m_mass;
	//	matrix33 invInertia = m_inertia.invert();
	//	FluidSparseVector angAccX(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//	FluidSparseVector angAccY(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//	FluidSparseVector angAccZ(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//	angAccX = invInertia[0][0] * m_TorqueX + invInertia[1][0] * m_TorqueY + invInertia[2][0] * m_TorqueZ;
	//	angAccY = invInertia[0][1] * m_TorqueX + invInertia[1][1] * m_TorqueY + invInertia[2][1] * m_TorqueZ;
	//	angAccZ = invInertia[0][2] * m_TorqueX + invInertia[1][2] * m_TorqueY + invInertia[2][2] * m_TorqueZ;
	//	m_TorqueX = angAccX;
	//	m_TorqueY = angAccY;
	//	m_TorqueZ = angAccZ;
	//}
}



void DecoRigidObject::Update(DOUBLE deltaTime)
{
	if (m_bTwowayCouple)
	{
		calculateMass();
		calculateInertia();

		int numAssociatedCells = static_cast<int>(m_associateGridIndex.size());
		vector3 totalForce(0, 0, 0);
		vector3 totalTorque(0, 0, 0);
		double area = m_grid->stepSize * m_grid->stepSize;
		vector3 force, dirFromOrigin, torque;
		for (int it = 0; it < numAssociatedCells; ++it)
		{
			int i = m_associateGridIndex[it].m_i;
			int j = m_associateGridIndex[it].m_j;
			int k = m_associateGridIndex[it].m_k;
			if (m_grid->isFluidCell(i + 1, j, k))
			{
				force = m_grid->p[i + 1][j][k] * area * vector3(-1, 0, 0);
				vector3 posGlobal = m_grid->GetGridCenter(i + 1, j, k) + vector3(-m_grid->stepSize / 2, 0, 0);
				dirFromOrigin = posGlobal - m_COM;
				dirFromOrigin.normalize();
				torque = CrossProduct(dirFromOrigin, force);

				totalForce += force;	
				totalTorque += torque;
			}
			if (m_grid->isFluidCell(i - 1, j, k))
			{
				force = m_grid->p[i - 1][j][k] * area * vector3(1, 0, 0);

				vector3 posGlobal = m_grid->GetGridCenter(i - 1, j, k) + vector3(m_grid->stepSize / 2, 0, 0);
				dirFromOrigin = posGlobal - m_COM;
				dirFromOrigin.normalize();
				torque = CrossProduct(dirFromOrigin, force);

				totalForce += force;	
				totalTorque += torque;

			}
			if (m_grid->isFluidCell(i, j + 1, k))
			{
				force = m_grid->p[i][j + 1][k] * area * vector3(0, -1, 0);

				vector3 posGlobal = m_grid->GetGridCenter(i, j + 1, k) + vector3(0, -m_grid->stepSize / 2, 0);
				dirFromOrigin = posGlobal - m_COM;
				dirFromOrigin.normalize();
				torque = CrossProduct(dirFromOrigin, force);

				totalForce += force;	
				totalTorque += torque;

			}
			if (m_grid->isFluidCell(i, j - 1, k))
			{
				force = m_grid->p[i][j - 1][k] * area * vector3(0, 1, 0);

				vector3 posGlobal = m_grid->GetGridCenter(i, j - 1, k) + vector3(0, m_grid->stepSize / 2, 0);
				dirFromOrigin = posGlobal - m_COM;
				dirFromOrigin.normalize();
				torque = CrossProduct(dirFromOrigin, force);

				totalForce += force;	
				totalTorque += torque;

			}
			if (m_grid->isFluidCell(i, j, k + 1))
			{
				force = m_grid->p[i][j][k + 1] * area * vector3(0, 0, -1);

				vector3 posGlobal = m_grid->GetGridCenter(i, j, k + 1) + vector3(0, 0, -m_grid->stepSize / 2);
				dirFromOrigin = posGlobal - m_COM;
				dirFromOrigin.normalize();
				torque = CrossProduct(dirFromOrigin, force);

				totalForce += force;	
				totalTorque += torque;

			}
			if (m_grid->isFluidCell(i, j, k - 1))
			{
				force = m_grid->p[i][j][k - 1] * area * vector3(0, 0, 1);

				vector3 posGlobal = m_grid->GetGridCenter(i, j, k - 1) + vector3(0, 0, m_grid->stepSize / 2);
				dirFromOrigin = posGlobal - m_COM;
				dirFromOrigin.normalize();
				torque = CrossProduct(dirFromOrigin, force);

				totalForce += force;	
				totalTorque += torque;

			}
		}

		updateRigidBody(totalForce, totalTorque, deltaTime);
	}
	else
	{
		INT currentPhase = getCurrentSegment();
		if (currentPhase >= 0)
		{
			m_vel += m_phaseAcc[currentPhase] * deltaTime;
		}
		else
		{
			m_vel += m_acc * deltaTime;
		}

		if (m_omg.lengthSqr() > EPSILON_FLOAT)
		{
			DOUBLE angle = m_omg.length() * deltaTime;
			vector3 rotateAxis = m_omg;
			rotateAxis.normalize();
			coords.RotateAlongGlobalVector(angle, rotateAxis);
		}
		vector3 translateOffset = m_vel * deltaTime;
		coords.Translate(translateOffset);

	}


	mesh.SetLocalToWorld(coords.GetMatrix());
	m_currentTime += deltaTime;
}

DecoRigidObject* DecoRigidObject::CreateFromMesh(const std::string & path)
{
	ifstream testStrm(path.c_str());
	if(testStrm.fail())
		return NULL;
	testStrm.close();
	DecoRigidObject* retval = new DecoRigidObject();
	if(!retval->CreateSceneObjectFromMesh(path))
	{
		delete retval;
		return NULL;
	}
	vector<char> name(retval->name.begin(), retval->name.end());
	vector<char>::reverse_iterator r1 = find(name.rbegin(), name.rend(), '\\');
	vector<char>::reverse_iterator r2 = find(name.rbegin(), name.rend(), '.');
	vector<char> section(r1.base(), r2.base()-1);
	section.push_back('\0');
	DecoConfig::GetSingleton()->GetBool(&(section[0]), "twoway", retval->m_bTwowayCouple);
	DecoConfig::GetSingleton()->GetDouble(&(section[0]), "rho", retval->m_rho);
	DecoConfig::GetSingleton()->GetVector3(&(section[0]), "vel", retval->m_vel);
	DecoConfig::GetSingleton()->GetVector3(&(section[0]), "acc", retval->m_acc);
	DecoConfig::GetSingleton()->GetVector3(&(section[0]), "omg", retval->m_omg);
	DecoConfig::GetSingleton()->GetInt(&(section[0]), "segments", retval->m_segments);
	vector3 startPos;
	if (DecoConfig::GetSingleton()->GetVector3(&(section[0]), "pos", startPos))
	{
		retval->GetCoords().SetOrigin(startPos);
	}
	retval->getMotionDescription();


	return retval;
}

void DecoRigidObject::allocateAllArrays()
{
	if (m_segments)
	{
		m_phaseAcc = new vector3[m_segments];
		m_phaseVel = new vector3[m_segments];
		m_phaseOmg = new vector3[m_segments];
		m_phaseDuration = new FLOAT[m_segments];
	}
}

void DecoRigidObject::destroyAllArrays()
{
	if (m_phaseAcc)
		delete[] m_phaseAcc;
	if (m_phaseOmg)
		delete[] m_phaseOmg;
	if (m_phaseVel)
		delete[] m_phaseVel;
	if (m_phaseDuration)
		delete[] m_phaseDuration;
	m_phaseAcc = m_phaseOmg = m_phaseVel = NULL;
	m_phaseDuration = NULL;
}

INT DecoRigidObject::getCurrentSegment()
{
	if (m_segments)
	{
		INT numIteration = static_cast<INT>(m_currentTime / m_oneLoopTime);
		DOUBLE timeInIteration = m_currentTime - numIteration * m_oneLoopTime;
		DOUBLE totalTime = 0;
		for (INT i = 0; i < m_segments; i++)
		{
			totalTime += m_phaseDuration[i];
			if (timeInIteration <= totalTime)
				return i;
		}
		return m_segments - 1;
	}
	else
		return -1;
}

void DecoRigidObject::getMotionDescription()
{
	static const INT keyLength = 128;
	DecoConfig::GetSingleton()->GetInt(name.c_str(), "segments", m_segments);

	if (m_segments)
	{
		allocateAllArrays();
		for (INT i = 0; i < m_segments; i++)
		{
			m_phaseAcc[i] = m_phaseVel[i] = m_phaseOmg[i] = vector3(0, 0, 0);
			m_phaseDuration[i] = 0;
			char keyName[keyLength];
			memset(keyName, 0, keyLength * sizeof(char));
			sprintf(keyName, "acc%d", i + 1);
			DecoConfig::GetSingleton()->GetVector3(name.c_str(), keyName, m_phaseAcc[i]);
			memset(keyName, 0, keyLength * sizeof(char));
			sprintf(keyName, "vel%d", i + 1);
			DecoConfig::GetSingleton()->GetVector3(name.c_str(), keyName, m_phaseVel[i]);
			memset(keyName, 0, keyLength * sizeof(char));
			sprintf(keyName, "omg%d", i + 1);
			DecoConfig::GetSingleton()->GetVector3(name.c_str(), keyName, m_phaseOmg[i]);
			memset(keyName, 0, keyLength * sizeof(char));
			sprintf(keyName, "duration%d", i + 1);
			DecoConfig::GetSingleton()->GetFloat(name.c_str(), keyName, m_phaseDuration[i]);
			m_oneLoopTime += m_phaseDuration[i];
		}
	}
}

FluidSparseVector DecoRigidObject::GetPressureContributionToUFaceAcc(int i, int j, int k, int dim)
{
	//FluidSparseVector ret(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//vector3 dirFromOrigin;
	//if (m_grid->isFluidCell(i - 1, j, k) && m_grid->isSolidCell(i, j, k))
	//{
	//	vector3 normal(1, 0, 0);
	//	vector3 posGlobal = m_grid->GetGridCenter(i - 1, j, k) + vector3(m_grid->stepSize / 2, 0, 0);
	//	dirFromOrigin = posGlobal - m_COM;
	//	dirFromOrigin.normalize();
	//	vector3 rCrossN = CrossProduct(dirFromOrigin, normal);
	//	ret = normal.x * m_ForceX + rCrossN.x * m_TorqueX + rCrossN.y * m_TorqueY + rCrossN.z * m_TorqueZ;
	//}
	//else if (m_grid->isFluidCell(i, j, k) && m_grid->isSolidCell(i - 1, j, k))
	//{
	//	vector3 normal(-1, 0, 0);
	//	vector3 posGlobal = m_grid->GetGridCenter(i, j, k) + vector3(-m_grid->stepSize / 2, 0, 0);
	//	dirFromOrigin = posGlobal - m_COM;
	//	dirFromOrigin.normalize();
	//	vector3 rCrossN = CrossProduct(dirFromOrigin, normal);
	//	ret = normal.x * m_ForceX + rCrossN.x * m_TorqueX + rCrossN.y * m_TorqueY + rCrossN.z * m_TorqueZ;

	//}
	//else
	//{
	//	(*DecoLogger::GetSingleton()) << "Should not reach here! GetPressureContributionToUFaceAcc(" << i << ", " << j << ", " << k <<").\n";
	//}
	//return ret;
	return getPressureContributionToUFaceAccForRigidBody(i, j, k, dim);
}
FluidSparseVector DecoRigidObject::GetPressureContributionToVFaceAcc(int i, int j, int k, int dim)
{
	//FluidSparseVector ret(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//vector3 dirFromOrigin;
	//if (m_grid->isFluidCell(i, j - 1, k) && m_grid->isSolidCell(i, j, k))
	//{
	//	vector3 normal(0, 1, 0);
	//	vector3 posGlobal = m_grid->GetGridCenter(i, j - 1, k) + vector3(0, m_grid->stepSize / 2, 0);
	//	dirFromOrigin = posGlobal - m_COM;
	//	dirFromOrigin.normalize();
	//	vector3 rCrossN = CrossProduct(dirFromOrigin, normal);
	//	ret = normal.y * m_ForceY + rCrossN.x * m_TorqueX + rCrossN.y * m_TorqueY + rCrossN.z * m_TorqueZ;
	//}
	//else if (m_grid->isFluidCell(i, j, k) && m_grid->isSolidCell(i, j - 1, k))
	//{
	//	vector3 normal(0, -1, 0);
	//	vector3 posGlobal = m_grid->GetGridCenter(i, j, k) + vector3(0, -m_grid->stepSize / 2, 0);
	//	dirFromOrigin = posGlobal - m_COM;
	//	dirFromOrigin.normalize();
	//	vector3 rCrossN = CrossProduct(dirFromOrigin, normal);
	//	ret = normal.y * m_ForceY + rCrossN.x * m_TorqueX + rCrossN.y * m_TorqueY + rCrossN.z * m_TorqueZ;

	//}
	//else
	//{
	//	(*DecoLogger::GetSingleton()) << "Should not reach here! GetPressureContributionToVFaceAcc(" << i << ", " << j << ", " << k <<").\n";
	//}
	//return ret;
	return getPressureContributionToVFaceAccForRigidBody(i, j, k, dim);
}
FluidSparseVector DecoRigidObject::GetPressureContributionToWFaceAcc(int i, int j, int k, int dim)
{
	//FluidSparseVector ret(m_grid->numXElement, m_grid->numYElement, m_grid->numZElement, dim);
	//vector3 dirFromOrigin;
	//if (m_grid->isFluidCell(i, j, k - 1) && m_grid->isSolidCell(i, j, k))
	//{
	//	vector3 normal(0, 0, 1);
	//	vector3 posGlobal = m_grid->GetGridCenter(i, j, k - 1) + vector3(0, 0, m_grid->stepSize / 2);
	//	dirFromOrigin = posGlobal - m_COM;
	//	dirFromOrigin.normalize();
	//	vector3 rCrossN = CrossProduct(dirFromOrigin, normal);
	//	ret = normal.z * m_ForceZ + rCrossN.x * m_TorqueX + rCrossN.y * m_TorqueY + rCrossN.z * m_TorqueZ;
	//}
	//else if (m_grid->isFluidCell(i, j, k) && m_grid->isSolidCell(i, j, k - 1))
	//{
	//	vector3 normal(0, 0, -1);
	//	vector3 posGlobal = m_grid->GetGridCenter(i, j, k) + vector3(0, 0, -m_grid->stepSize / 2);
	//	dirFromOrigin = posGlobal - m_COM;
	//	dirFromOrigin.normalize();
	//	vector3 rCrossN = CrossProduct(dirFromOrigin, normal);
	//	ret = normal.z * m_ForceZ + rCrossN.x * m_TorqueX + rCrossN.y * m_TorqueY + rCrossN.z * m_TorqueZ;

	//}
	//else
	//{
	//	(*DecoLogger::GetSingleton()) << "Should not reach here! GetPressureContributionToWFaceAcc(" << i << ", " << j << ", " << k <<").\n";
	//}
	//return ret;
	return getPressureContributionToWFaceAccForRigidBody(i, j, k, dim);
}


DecoArchive& operator<< (DecoArchive& Ar, const DecoRigidObject& obj)
{
	Ar << obj.m_segments;

	const DecoSolidObject* solidObj = static_cast<const DecoSolidObject*>(&obj);
	Ar << (*solidObj);
	return Ar;
}

DecoArchive& operator>> (DecoArchive& Ar, DecoRigidObject& obj)
{
	Ar >> obj.m_segments;
	DecoSolidObject* solidObj = static_cast<DecoSolidObject*>(&obj);
	Ar >> (*solidObj);
	obj.getMotionDescription();
	return Ar;

}